//Crazy Intro, Copyright 2009 WiiCrazy/I.R.on of Irduco (nejat@tepetaklak.com)
//Distributed under the terms of the GNU GPL v2.0
//See http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt for more information

//ONGOING WORK
//For 0.8 : Theme support from folders
//		Features
//			Split config (done)
//			Increase filename strings sizes (done)
//			Make A & B buttons configurable (done)
//			Make 1, 2, +, - buttons configurable (done)
//			Change music ending boot behaviour and make it configurable. (done)
//			Experimental dol/elf loading (done)
//		Bugs
//			Unassigned button launching menu bugfix (fixed)
//			Birthday picture offsets affecting boot picture offsets bug (fixed)
//			Default intro borked with the above unassigned button fix :) (fixed)

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <fat.h>
#include <sys/dir.h>
#include <unistd.h>
#include <errno.h>
#include <mp3player.h>
#include "core/common.h"
#include "core/config.h"
#include <jpeg/jpgogc.h>
#include <network.h>
#include "core/syslog.h"
#include <GRRLIB.h>
#include <gcmodplay.h> 
#include <mii.h>
#include <time.h>
#include "core/keys.h"
#include "core/action.h"
#include "dir.h"
#include "rendermii.h"

#define DEBUG_SERVER_IP "192.168.2.4"

//************** REAL GLOBALS *****************

#ifdef DEBUG
	syslog_instance_t *syslog;
#endif


#include "effects.h"

#define APP_FILES_BASE  "sd:/crazyintro/"

static u32 black;

//************** GLOBALS *****************
//unsigned char * picdata;
unsigned char * picdata;
int piclength;
unsigned char * presspicdata;
int presspiclength;
char * musicdata;
int  musiclength;
u8 HWButton = 0;

bool externalSoundLoaded = false;
bool customPressPicLoaded = false;
bool customBootLogoLoaded = false;
bool isExternalSoundMp3 = false;
bool isExternalSoundMod = false;

bool useDefaultIntro = false;

GRRLIB_texImg * intro;
static GRRLIB_texImg * custom_boot_logo;
static GRRLIB_texImg * custom_press_img;

static GRRLIB_texImg * miiTexture;
GRRLIB_texImg *miiTextures[10];


MODPlay modMusic;

GRRLIB_texImg * birthdayPicture;
MODPlay birthdayMusic;

int birthdayMusicLength;
unsigned char * birthdayMusicData;
unsigned char * birthdayPictureData;

bool continueRead=false;
int activeWiimote = -1;
s32 pressed;
s32 held;
ir_t ir;

char actualTheme[255];
bool cycleOrRandom;


//---------------------------------------------------------------------------------
int Net_Init(char *ip)
{
    printf("Waiting for network to initialise...\n");
	
	s32 res;
	
	while ((res = net_init()) == -EAGAIN);
	
    if (res >= 0) 
	{
        if (if_config(ip, NULL, NULL, true) < 0)
		{
			printf("Error reading IP address\n");
			return FALSE;
        }
		printf("Network initialised\n");
		return TRUE;
    } 
	else 
	{
        printf("Unable to initialise network\n");
		return FALSE;
    }
}


/**
 * Callback for the reset button on the Wii.
 */
void WiiResetPressed()
{
	HWButton = SYS_RETURNTOMENU;
}
 
/**
 * Callback for the power button on the Wii.
 */
void WiiPowerPressed()
{
	HWButton = SYS_POWEROFF_STANDBY;
}
 
/**
 * Callback for the power button on the Wiimote.
 * @param[in] chan The Wiimote that pressed the button
 */
void WiimotePowerPressed(s32 chan)
{
	HWButton = SYS_POWEROFF_STANDBY;
}


int GetEnumerationForTheDay(int start, int end) 
{
	time_t timer;                // Define the timer

	// Get time of day
	timer = time(NULL);
	
	int totalDays = timer/86400;
	
	return (totalDays % (end-start)) + start;
}

int GetRandomEnumeration(int start, int end) 
{
	int count = end-start + 1;
	srand((unsigned int)time((time_t *)NULL));
	int selectedRandom = (int)(rand() / (((double)RAND_MAX + 1)/ count));
	return selectedRandom + start;
}


GRRLIB_texImg * loadThemeTexture(char * filename, bool enumerate, bool cycleOrRandom, int start, int end) 
{

	char imageFile[255];
	int enumeration;
	
	strcpy(imageFile, APP_FILES_BASE);
	strcat(imageFile, actualTheme);
	strcat(imageFile, "/");
	
	if (enumerate) 
	{
		//Now get the enumeration regarding the stuff we'll display.
		if (cycleOrRandom) 
		{
			#ifdef DEBUG
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Getting enumeration for today");
			#endif			
			enumeration = GetEnumerationForTheDay(start, end);
		} else 
		{
			#ifdef DEBUG
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Getting random enumeration");
			#endif			
		
			enumeration = GetRandomEnumeration(start, end);
		}
		char * p;
		
		if ((p=strstr(filename, "%%%%"))!=NULL) 
		{
			#ifdef DEBUG
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "File has delimiter with the width of 4");
			#endif		
			//0-9999		
			char index[5];
			snprintf(index, 5, "%04d", enumeration);
			
			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Prepared enumeration is : %s", index);
			#endif		
			
			memcpy(p, index, 4);		
			
		} else if ((p=strstr(filename, "%%%"))!=NULL) 
		{
			#ifdef DEBUG
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "File has delimiter with the width of 3");
			#endif		
		
			//0-999		
			char index[4];
			snprintf(index, 4, "%03d", enumeration);
			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Prepared enumeration is : %s", index);
			#endif		
			
			memcpy(p, index, 3);		
		} else if ((p=strstr(filename, "%%"))!=NULL) 
		{
			#ifdef DEBUG
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "File has delimiter with the width of 2");
			#endif		
		
			//0-99
			char index[3];
			snprintf(index, 3, "%02d", enumeration);
			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Prepared enumeration is : %s", index);
			#endif		
			
			memcpy(p, index, 2);		
		} else if ((p=strstr(filename, "%"))!=NULL) 
		{
			#ifdef DEBUG
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "File has delimiter with the width of 1");
			#endif		
		
			//0-9
			char index[2];
			snprintf(index, 2, "%01d", enumeration);
			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Prepared enumeration is : %s", index);
			#endif		
			
			memcpy(p, index, 1);

			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Final filename is : %s", filename);
			#endif				
		} 
		
		//Just replace the correct placeholders.
	} 
	
	strcat(imageFile, filename);	

	#ifdef DEBUG
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Full filename is : %s", imageFile);
	#endif				

	return GRRLIB_LoadTextureFromFile(imageFile);	
}


void lowCase(char * val) 
{
	//Convert filename in lowercase to lowCaseFile variable
	int i = 0;
	while(val[i]!=NULL) 
	{
		val[i] = tolower(val[i]);
		i++;
	}
}

void upperCase(char * val) 
{
	//Convert filename in lowercase to lowCaseFile variable
	int i = 0;
	while(val[i]!=NULL) 
	{
		val[i] = toupper(val[i]);
		i++;
	}
}

#define FILE_TYPE_UNKNOWN 0
#define MOD_FILE 1
#define MP3_FILE 2


int loadSoundFromSdCardGeneric(char * filename, void ** musicBuffer, int * length) 
{
	#ifdef DEBUG
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Filename is:  %s", filename);
	#endif
	int fileType = FILE_TYPE_UNKNOWN;
	char musicImageFile[255];
	char lowCaseFile[255];
	void *buffer = NULL;
	
	if (filename != NULL) {
		strcpy(musicImageFile, APP_FILES_BASE);
		strcat(musicImageFile, actualTheme);
		strcat(musicImageFile, "/");		
		strcat(musicImageFile, filename);
		
		#ifdef DEBUG
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Checking if this one is a :  %s", musicImageFile);
		#endif
		
		strcpy(lowCaseFile, musicImageFile);
		lowCase(lowCaseFile);
		
		#ifdef DEBUG
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Lower case version is:  %s", lowCaseFile);
		#endif

		char * modSearch = strstr(lowCaseFile, ".mod");
		if (modSearch!=NULL) {
			fileType = MOD_FILE;
			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Yep a mod file:  %s", "");
			#endif			
		}
	
		char * mp3Search = strstr(lowCaseFile, ".mp3");
		if (mp3Search!=NULL) {
			fileType = MP3_FILE;
			#ifdef DEBUG
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Nopez it's an mp3:  %s", "");
			#endif					
		}
		
		if (fileType!=FILE_TYPE_UNKNOWN) {
			FILE * s = HEDE_OpenContent(musicImageFile);
			if(s==NULL) {
				return -1;
			}
			
			HEDE_SeekContent(s, 0, SEEK_END);
			*length = ftell(s);
			buffer = malloc(*length);	
			HEDE_SeekContent(s, 0, SEEK_SET);
			HEDE_ReadContent(s, buffer, *length);
			HEDE_CloseContent(s);
			*musicBuffer=buffer;
			return fileType;			
		} 
		return fileType;
	} else 
	{
		return fileType;
	}
}	



int loadSoundFromSdCard() {

	#ifdef DEBUG
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Intro music is:  %s", GetIntroMusic());
	#endif

	char musicImageFile[80];
	char lowCaseFile[80];
	
	if (GetIntroMusic() != NULL) {
		strcpy(musicImageFile, GetIntroMusic());
		int fileType = loadSoundFromSdCardGeneric(musicImageFile, &musicdata, &musiclength);
		if (fileType == MP3_FILE) 
		{
			isExternalSoundMp3 = true;			
			return 1;
		} else if (fileType == MOD_FILE)  
		{		
			isExternalSoundMod = true;
			return 1;
		}		
	} else 
	{
		return 0;
	}
}	


void my_exit()
{
	WPAD_Shutdown();
	usleep(500); 
	
	if (externalSoundLoaded) {
		if (MP3Player_IsPlaying())  {
			MP3Player_Stop();
			usleep(500); 
		} 
	}
	
	SYS_ResetSystem(HWButton, 0, 0);
	
	exit(0);
}



void Initialise() {
    //VIDEO_Init();  
    GRRLIB_Init();
	ClearScreen();
	WPAD_SetVRes(0, 640, 480);
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);	
	WPAD_Init();
		
	SYS_SetResetCallback(WiiResetPressed);
	SYS_SetPowerCallback(WiiPowerPressed);
	WPAD_SetPowerButtonCallback(WiimotePowerPressed);			
}


bool tryToGetActiveWiimote() 
{	
	int i;
	for(i = 0; i < 4; i++)
	{
		int mote = (WPAD_Probe(i, NULL) == WPAD_ERR_NONE);
		if (mote) 
		{
			activeWiimote=i;
			return true;
		}
	}		
	
	return false;
}


void stopMusic() 
{
	if (externalSoundLoaded) {
	
		if (isExternalSoundMp3) {
			if (MP3Player_IsPlaying())  {
				MP3Player_Stop();
			}
		} else if (isExternalSoundMod) 
		{
			MODPlay_Stop(&modMusic);
		}
		
		ASND_End();
	}
}


s32 read_pad()
{	
	s32 pressed;
	while(1)
	{
		WPAD_ScanPads();
		//WPAD_IR(0, &ir);		
		pressed = WPAD_ButtonsDown(0);
		if(pressed)
			return pressed;
		VIDEO_WaitVSync();
	}
	return pressed;
}

void InitMusic() 
{
	if (externalSoundLoaded) 
	{
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Initting custom sound");	
		#endif
		ASND_Init();
		if (isExternalSoundMp3) {
			MP3Player_Init();
			MP3Player_PlayBuffer(musicdata,musiclength,NULL);
		} else if(isExternalSoundMod) 
		{
			MODPlay_Init(&modMusic);
			MODPlay_SetMOD(&modMusic, musicdata);
			MODPlay_Start(&modMusic);   
		}
	}

}

int bootLogoWidth;

void InitializeStuff() 
{
	InitFont();


	#ifdef DEBUG 
		Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Initializing stuff");
	#endif

	#ifdef DEBUG 
		Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Loading boot logo");
	#endif

	//custom_boot_logo = GRRLIB_LoadTexturePNG(picdata);
	
	if (!useDefaultIntro) 
	{

		if (strstr(GetBootImage(), "%")!=NULL) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "we have random/sequential boot logo");
			#endif
		
			if (strcmp(GetBootImageEnumeration(), "cycle")==0)
			{
				#ifdef DEBUG 
					Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "cycle type selected");
				#endif
			
				custom_boot_logo = loadThemeTexture(GetBootImage(), true, true, GetBootImageStart(), GetBootImageEnd());
			} else 
			{
				#ifdef DEBUG 
					Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "random type selected");
				#endif
			
				custom_boot_logo = loadThemeTexture(GetBootImage(), true, false, GetBootImageStart(), GetBootImageEnd());			
			} 
		} else 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "we don't have random/sequential boot logo");
			#endif
		
			custom_boot_logo = loadThemeTexture(GetBootImage(), false, false, 0, 0); 
		}
	
		if (custom_boot_logo!=NULL) 
		{	
			#ifdef DEBUG 
				Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "boot logo loaded, initing tileset %d", TILEHEIGHT);
			#endif
				
			//TODO: Check if tearing effects used
			GRRLIB_InitTileSet(custom_boot_logo, custom_boot_logo->w, TILEHEIGHT, 0); //Offset 0, height/TILEHEIGHT tiles each with TILEHEIGHT pixel widths
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "tileset initialized");
			#endif
			GRRLIB_SetMidHandle(custom_boot_logo, true);
			customBootLogoLoaded = true;			
		} else 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "boot logo not loaded");
			#endif
		
			customBootLogoLoaded = false;
		}


		#ifdef DEBUG 
		Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Loading custom press pic texture");
		#endif

		//custom_press_img = GRRLIB_LoadTexturePNG(presspicdata);
		custom_press_img = loadThemeTexture(GetPressImage(), false,false, 0, 0);
		if (custom_press_img!=NULL) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "custom press pic texture loaded");
			#endif	
			
			int pressImageEffect = GetPressImageEffect();
			if (pressImageEffect !=PI_FADEINOUT) 
			{
				int piTileWidth = GetPressImageTileWidth();
				int piTileHeight = GetPressImageTileHeight();
				GRRLIB_InitTileSet(custom_press_img, piTileWidth,piTileHeight, 0); //Offset 0, height/TILEHEIGHT tiles each with TILEHEIGHT pixel widths		
			}
			customPressPicLoaded = true;
		} else 
		{
			customPressPicLoaded = false;
		}
		
		if ((!customBootLogoLoaded)|| (!customPressPicLoaded)) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "One of boot picture or press picture not loaded, defaulting");
			#endif	
			
	
			useDefaultIntro = true;
		}

		
	}
	
	
	if (!useDefaultIntro) {
		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Setting custom intro defaults");
		#endif		
		bootLogoWidth = custom_boot_logo->h;	
		setDefaults(customBootLogoLoaded, 
					GetBootImageOffsetX(),
					GetBootImageOffsetY(), 
					GetPressImageOffsetX(),
					GetPressImageOffsetY(), 
					bootLogoWidth,
					GetPressImageEffect(),
					GetPressImageTileWidth(),
					GetPressImageTileHeight(),
					GetPressImageTileOrdering(),
					GetPressImageAnimationSpeed(),
					GetPressImageScale()
					) ;
	} else 
	{
		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Setting default intro defaults");
		#endif		
	
		setDefaults(customBootLogoLoaded, 0 ,0, 0, 0,  0, 
					GetPressImageEffect(),
					GetPressImageTileWidth(),
					GetPressImageTileHeight(),
					GetPressImageTileOrdering(),
					GetPressImageAnimationSpeed()) ;		
	}
	#ifdef DEBUG 
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Defaults set");
	#endif			

}
 
 
void InitBirthdayMusic(int type) 
{
	#ifdef DEBUG 
		Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Initting custom sound");	
	#endif
	ASND_Init();
	if (type == MP3_FILE) {
		MP3Player_Init();
		MP3Player_PlayBuffer(birthdayMusicData,birthdayMusicLength,NULL);
	} else if(type == MOD_FILE) 
	{
		MODPlay_Init(&birthdayMusic);
		MODPlay_SetMOD(&birthdayMusic, birthdayMusicData);
		MODPlay_Start(&birthdayMusic);   
	}


}


int InitBirthdayStuff(char * greeting) 
{
	if (!useDefaultIntro) 
	{
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Initting birthday stuff (custom)");	
		#endif
	
		u16 x_offset = GetBirthdayImageOffsetX();
		u16 y_offset = GetBirthdayImageOffsetY();	
		char * birthdayImageFile = GetBirthdayImage();
		char * birthdayMusicFile = GetBirthdayMusic();	
		
		int fileType = loadSoundFromSdCardGeneric(birthdayMusicFile, &birthdayMusicData, &birthdayMusicLength);
		//loadPicFromSdCardGeneric(birthdayImageFile, &birthdayPictureData);
		birthdayPicture = loadThemeTexture(birthdayImageFile, false,false, 0, 0);		
		GRRLIB_SetMidHandle(birthdayPicture, true);
		setBirthdayDefaults(true, x_offset, y_offset);
		InitBirthdayMusic(fileType);
		return fileType;		
	} else 
	{
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Initting birthday stuff (default)");	
		#endif
	
		setBirthdayDefaults(false, 0, 0);	
		InitDefaultBirthday();
	}

	return 0;	
}


void FinishBirthdayStuff(int musicFileType) 
{
	#ifdef DEBUG 
		Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Finishing birthday stuff");	
	#endif


	if (!useDefaultIntro) {

		if (musicFileType==FILE_TYPE_UNKNOWN) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Unknown, doing nothing");	
			#endif
		
			return;
		}
	
		if (musicFileType==MP3_FILE) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: custom mp3 file, stopping...");	
			#endif
		
			if (MP3Player_IsPlaying())  {
				MP3Player_Stop();
				usleep(500); 
			} 
		} else if (musicFileType==MOD_FILE) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: custom mod file, stopping...");	
			#endif
		
			int i;
			for (i=255;i>=0;i-=5) 
			{
				ASND_ChangeVolumeVoice(0, i, i);
				usleep(50000);
			}
			MODPlay_Stop(&birthdayMusic);
		}
	} else 
	{
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Finishing birthday stuff (default)");	
		#endif
	
		FinishDefaultBirthdayStuff();
	}
}

void DoBirthdayStuff(int musicType, char * greeting, int miisWithBirthDay[], int miiBirthdayCount) 
{
	s32 pressed;
	s32 held;
	bool continueRead = false;
	
	int frame = 0;
	while(!continueRead) 
	{		
		WPAD_ScanPads();
		pressed = WPAD_ButtonsDown(0);
		held = WPAD_ButtonsHeld(0);
	
	
		// Test the keys and determine if we'll be exiting
		if(HWButton) break;
		
		if(pressed)
		{
			continueRead = true;
		}
					
		if (!useDefaultIntro) 
		{
			do_birthday_stuff(birthdayPicture,  miiBirthdayCount, miiTextures, greeting);
		} else 
		{
			do_default_birthday_stuff(miiBirthdayCount, miiTextures, greeting);
		}				
		
		GRRLIB_DrawImg(300, 150, miiTexture,  0, 1, 1, 0xFFFFFFFF);		
		GRRLIB_Render();
		frame++;
		frame = frame%200;
		
	}	

	FinishBirthdayStuff(musicType);
	
	if(HWButton) 
	{
		my_exit();
	}	

}

bool SetSelectedTheme(char * selectedTheme) 
{
	if (!strcmp(selectedTheme, "random")) 
	{
		//Read the directory under crazy intro folder	
		DIR_ITER*   root;
		struct stat fInfo;
		int         fCount = 0;	
		
		directoryView dView[255];
		root = diropen(APP_FILES_BASE);
		if (root) {
			
			while (dirnext(root, dView[fCount].fName, &fInfo) == 0) {
	
				if(fInfo.st_mode & S_IFDIR) 
				{
					if ((strcmp(dView[fCount].fName, ".") != 0) &&  (strcmp(dView[fCount].fName, "..") != 0) )  {
						#ifdef DEBUG 
							Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, dView[fCount].fName);
						#endif	

						dView[fCount].isDirectory = 1;
						fCount++;			
					}
				}
			}		  

			#ifdef DEBUG 
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "Theme count is : %d", fCount);
			#endif	

			//Now folders read... just select one out of 1..fCount folders
			
			srand((unsigned int)time((time_t *)NULL));
			int selectedRandom = (int)(rand() / (((double)RAND_MAX + 1)/ fCount));

			#ifdef DEBUG 
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "Selected Theme is : %d", selectedRandom);
			#endif	
			
			#ifdef DEBUG 
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "Selected Theme name is : %s", dView[selectedRandom].fName);
			#endif	
			
			strcpy(actualTheme, dView[selectedRandom].fName);			
			LoadThemeConfig(actualTheme); 


		}
		else {
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: no folders under crazyintro folder?");
		#endif	
			return NULL;		
		}
	} else 
	{
		strcpy(actualTheme, GetSelectedTheme());
		LoadThemeConfig(actualTheme); 
		return true;
	}
}

//---------------------------------------------------------------------------------
int main(int argc, char **argv) { 
//--------------------------------------------------------------------------------
	int introEffect, pictureEffect, outroEffect;

	Initialise();

#ifdef DEBUG	
	char myIP[16];
	if( !Net_Init(myIP) )
	{
		printf("exiting ..");
		return 0;
	}
#endif
	
	
#ifdef DEBUG	
	syslog = Syslog_Start("wii");
	if( !syslog )
	{
		printf("\x1b[35mSYSLOG FAILED TO INITIALIZE\n\x1b[0m");
		return 0;
	}
	Syslog_SetDestination(syslog, DEBUG_SERVER_IP, 514);
	//Syslog_SetDestination(syslog, "192.168.2.11", 514);	
    Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: starting");
	effectsSetDebugInstance(syslog);
	keysSetDebugInstance(syslog);
	actionSetDebugInstance(syslog);
	configSetDebugInstance(syslog);
#endif
	
	int result = fatInitDefault();
	
	useDefaultIntro = true;
	
	//if (true) 
	if (!ConfigExists()) 
	{
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: no config");
		#endif
		useDefaultIntro = true;
		//CreateConfigFile();
	} 
	else {
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: loading config");
		#endif	
		useDefaultIntro = false;		
		
		LoadConfigFile();		
	
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: config loaded");
		#endif	


		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: loading theme config");
		#endif	

		//Load the selected theme config
		char * selectedTheme = GetSelectedTheme();
		SetSelectedTheme(selectedTheme);
		

	
		#ifdef DEBUG 
			Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: theme config loaded");
		#endif	

		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: config has %d titles configured", GetTitleCount());
		#endif	

		#ifdef DEBUG 
			if (GetTitleCount()) {
				Title * title;
				title = GetTitle(0);
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: TitleId 0x%016llx", title->titleId);				
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Mnemonic %s", title->titleMnemonic);
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Name %s", title->titleName);								
			}
		#endif	

		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: config has %d shortcuts configured", GetShortcutCount());
		
			if (GetShortcutCount()>1) {
				Shortcut * shortcut;
				shortcut = GetShortcut(1);
				char * keyIdentifier;
				keyIdentifier = GetKeyIdentifier(shortcut->assignedKey);
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: 1. Assigned Key %d", shortcut->assignedKey);												
				Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: 1. Assigned Key Identifier %s", keyIdentifier);																
				if (keyIdentifier!=NULL) 
				{
					Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: 1. Assigned Key %s", keyIdentifier);				
				}

				if (shortcut->titleIndex>=0) 
				{
					Title * title;
					title = GetTitle(shortcut->titleIndex);
					Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Points to Title %s", title->titleMnemonic);
				} else {
					Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: Points to Menu");
				}
			}
		#endif	
		
/*
		if (loadPicFromSdCard()) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: custom boot picture loaded");	
			#endif
			customBootLogoLoaded = true;

			#ifdef DEBUG 
				if (picdata) 
				{
					Syslog_SendFormat(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "first byte of picture %x", picdata[0]);	
				} else 
				{
					Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "Null picdata pointer");					
				}
			#endif

		} else 
		{
			useDefaultIntro = false;
		}

		if (loadPressPicFromSdCard()) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: custom press picture loaded");	
			#endif
			customPressPicLoaded = true;
			
		}
*/		
	}
	
	InitializeStuff();	

	if (IsBirthdayFunctionEnabled()) 
	{
	
	 #ifdef DEBUG 				
	 	Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Loading Miis");
	 #endif
	 	Mii * miis;
	 	miis = loadMiis_Wii();

		//Getting current day & month to check if any miis have a birthday
		time_t timer;                // Define the timer
		struct tm *tblock;           // Define a structure for time block

		// Get time of day
		timer = time(NULL);

		// Converts date/time to a structure
		tblock = localtime(&timer);
		int currentDay = tblock->tm_mday;
		int currentMonth = tblock->tm_mon+1;


		#ifdef DEBUG 																		
		if (tblock) 
		{
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Current day : %d", currentDay);			 
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Current month : %d", currentMonth);		
		}
		#endif
		
		bool gotAnyMiisBirthDay = false;
		char miisHaveBirthDay[128];
		char birthdayGreeting[256];
		
		strcpy(miisHaveBirthDay,"");
		strcpy(birthdayGreeting,"");
		
		#ifdef DEBUG 																		
	 	Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Miis loaded");		
		#endif
		
	 	int i=0;
		int miiIndex[10];
		int miiBirthdayCount = 0;
		
	 	bool invalid = false;
	 	for (i=0;i<100;i++)
	 	{
	 		if (miis[i].month>0 && miis[i].day>0) {				
				if ((miis[i].month == currentMonth) && (miis[i].day == currentDay) )
				{
					gotAnyMiisBirthDay = true;
					#ifdef DEBUG 											
					Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "%s have a birthday", miis[i].name);																
					#endif
					if (strlen(miisHaveBirthDay)>0) 
					{
						#ifdef DEBUG 																
						Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "we have more than one so delimiting them");
						#endif
						strcat(miisHaveBirthDay, ", ");
					}
					strcat(miisHaveBirthDay, miis[i].name);					
					if (miiBirthdayCount<10) 
					{
						miiIndex[miiBirthdayCount] = i;
						miiBirthdayCount++;
					}
				}
				#ifdef DEBUG 						
					Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Miis name : %s", miis[i].name);												
					Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Miis creator : %s", miis[i].creator);				
					Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Miis birthdate : %i/%i", miis[i].month, miis[i].day);															
				#endif
	 		}
	 	}
	
		if (gotAnyMiisBirthDay) 
		{
			initmii(miis);
			upperCase(miisHaveBirthDay);
			strcpy(birthdayGreeting, "HAPPY BIRTHDAY ");
			strcat(birthdayGreeting, miisHaveBirthDay);
			strcat(birthdayGreeting, "!!!");
			int musicType = InitBirthdayStuff(birthdayGreeting);
			
		    for(i=0; i<miiBirthdayCount; i++) {
				miiTextures[i] = GRRLIB_CreateEmptyTexture(180, 200);
				GRRLIB_BuildMii(miis[miiIndex[i]], 0, 0, 0, miiTextures[i]); 
			}
			//miiTexture = GRRLIB_CreateEmptyTexture(180, 200);
			//GRRLIB_BuildMii(miis[miiIndex[0]], 0, 0, 0, miiTexture);	
			
			DoBirthdayStuff(musicType, birthdayGreeting, miiIndex, miiBirthdayCount);	
		}
		
		#ifdef DEBUG
			Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Initing miis start");
		#endif	
		
		#ifdef DEBUG
			Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Initing miis end");
		#endif	

	}


	
	if (!useDefaultIntro) {
		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Intro effect is %s", GetIntroEffect());
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Picture effect is %s", GetPictureEffect());
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Outro effect is %s", GetOutroEffect());
		#endif	
		introEffect = convertIntroEffect(GetIntroEffect());
		pictureEffect = convertPictureEffect(GetPictureEffect());
		outroEffect = convertOutroEffect(GetOutroEffect());

		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Will do Intro effect %d with param1=%d, param2=%d", introEffect,GetIntroEffectParam1()  , GetIntroEffectParam2());
		#endif

		do {
		} while(do_picture_stuff(ET_INTRO, introEffect, GetIntroEffectParam1()  , GetIntroEffectParam2(),  custom_boot_logo, custom_press_img)); //TODO: parameterize options

		if (loadSoundFromSdCard()) 
		{
			#ifdef DEBUG 
				Syslog_Send(syslog, SYSLOG_PRI_INTERNAL, SYSLOG_SEV_DEBUG, "syslog: custom music loaded");		
			#endif
			externalSoundLoaded = true;
		}	
		
		InitMusic();
		
		#ifdef DEBUG 
			Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Will do Picture effect %d with param1=%d, param2=%d", pictureEffect,GetPictureEffectParam1()  , GetPictureEffectParam2());
		#endif
		
	} else 
	{ 
		StartDefaultIntroMusic();
	}


	s8 currentKey = _NOKEY;
	s8 hiddenShortcutIndex = CANDIDATE_CONTINUE;	
	bool doingAutoboot = false;
	
	setConfig(useDefaultIntro);
	while(!continueRead) 
	{			
		if (!useDefaultIntro) 
		{
			do_picture_stuff(ET_PICTURE, pictureEffect, GetPictureEffectParam1() ,GetPictureEffectParam2(), custom_boot_logo,custom_press_img); //TODO: parameterize options
		} 
		else 
		{
			do_default_picture_stuff();
		}

		// Test the keys and determine if we'll be exiting
		if(HWButton) break;
		
		//Scan keys
		WPAD_ScanPads();
			
		if (tryToGetActiveWiimote()) 
		{
			pressed = WPAD_ButtonsDown(activeWiimote);held = WPAD_ButtonsHeld(activeWiimote); 
						
			currentKey = respondToKey(pressed, held, &hiddenShortcutIndex);	

			
			if (currentKey!=_NOKEY) 
			{
				continueRead=true;
			}
		}
		
		if (externalSoundLoaded) {
			if (isExternalSoundMp3) {
				if (!MP3Player_IsPlaying()) 
				{
					continueRead = true;
					doingAutoboot = true;
				}
			}
		}

	}	

	#ifdef DEBUG 
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Will do Outro effect %d with param1=%d, param2=%d", outroEffect,GetOutroEffectParam1()  , GetOutroEffectParam2());
	#endif

	if (!useDefaultIntro) {
		//Do the outro
		do {
			//VIDEO_WaitVSync();
		} while(do_picture_stuff(ET_OUTRO, outroEffect, GetOutroEffectParam1() , GetOutroEffectParam2(), custom_boot_logo,custom_press_img));
		stopMusic();
	} else 
	{
		ShutdownDefaultIntro();
	}
	//Now handle the keypresses actually... 


	if(HWButton) 
	{
		my_exit();
	}


	#ifdef DEBUG 
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Pressed key is %d", currentKey);
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Hidden shortcut is %d", hiddenShortcutIndex);
		Syslog_SendFormat(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "Default Intro? %s", useDefaultIntro? "default": "custom");
		
		sleep(2);
	#endif

	handleKeyAction(currentKey, doingAutoboot, useDefaultIntro, hiddenShortcutIndex);

	

#ifdef DEBUG 	
	Syslog_Send(syslog, SYSLOG_PRI_LOCAL0, SYSLOG_SEV_DEBUG, "No keys pressed, booting menu");	
#endif
	
#ifdef DEBUG
    Syslog_Send(syslog, 0, 0, "WIILOADSYSLOG:EXIT");
    Syslog_End(syslog);
#endif
	
	exitToSystemMenu(); 
	
}
